﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using PUCLibrary;

namespace WebRamosUCWebCrawler
{
    //<delegates>
    public delegate int AddFromUrlCallback(string carrera, List<string> url);
    public delegate void SaveRamosToFile(string path);
    //</delegates>

    /// <summary>
    /// Controlador principal del programa, tiene toda la logica entre la vista y el modelo.
    /// </summary>
    public class MainController
    {
        //Fields:
        private Dictionary<string, Ramo> ramos;     //Dict. con todos los ramos cargados <"sigla", "Ramo">
        private Dictionary<string, List<string>> urlDict; //Dict. <"nombre", "url"> donde estan info de los ramos
        private string periodo;     //El periodo que ha sido cargado desde archivo. (Ej: "2-2010")
        MainForm cargarDatosForm;

        /// <summary>
        /// Constructor. 
        /// Se usa desde el Main()
        /// </summary>
        public MainController()
        {
            ramos = new Dictionary<string, Ramo>();
            CargarUrlRamos();

            //Nos colgamos del logger:
            Logger.Instance.MessageAdded += new Action<string>(Logger_MessageAdded);
        }

        /// <summary>
        /// Carga la lista de URL desde el archivo ".\ListaCursoURL.txt".
        /// </summary>
        private void CargarUrlRamos()
        {
            urlDict = new Dictionary<string, List<string>>();
            #region Carga de URL's (2do semestre)
            //urlDictTemp.Add("OFG Ingenieria", "http://www.puc.cl/dara/libcursos/periodo22/lic/lic_ingenieria_data.html");
            //urlDictTemp.Add("Actuación", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_34_data.html");
            //urlDictTemp.Add("Agronomía e Ingeniería Forestal", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_11_data.html");
            //urlDictTemp.Add("Arquitectura", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_94_data.html");
            //urlDictTemp.Add("Arte", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_33_data.html");
            //urlDictTemp.Add("Ciencias Biológicas", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_12_data.html");
            //urlDictTemp.Add("Ciencias Económicas y Administrativas", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_5_data.html");
            //urlDictTemp.Add("Ciencia Política", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_45_data.html");
            //urlDictTemp.Add("Comunicaciones", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_28_data.html");
            //urlDictTemp.Add("Construcción Civil", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_1_data.html");
            //urlDictTemp.Add("Derecho", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_17_data.html");
            //urlDictTemp.Add("Diseño", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_59_data.html");
            //urlDictTemp.Add("Educación", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_20_data.html");
            //urlDictTemp.Add("Enfermería", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_13_data.html");
            //urlDictTemp.Add("Estética", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_51_data.html");
            //urlDictTemp.Add("Estudios Urbanos", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_95_data.html");
            //urlDictTemp.Add("Filosofía", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_67_data.html");
            //urlDictTemp.Add("Física", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_3_data.html");
            //urlDictTemp.Add("Geografía", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_57_data.html");
            //urlDictTemp.Add("Historia", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_56_data.html");
            //urlDictTemp.Add("Ingeniería", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_4_data.html");
            //urlDictTemp.Add("Letras", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_64_data.html");
            //urlDictTemp.Add("Matemática", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_6_data.html");
            //urlDictTemp.Add("Medicina", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_14_data.html");
            //urlDictTemp.Add("Música", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_70_data.html");
            //urlDictTemp.Add("Psicología", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_29_data.html");
            //urlDictTemp.Add("Química", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_10_data.html");
            //urlDictTemp.Add("Sociología", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_91_data.html");
            //urlDictTemp.Add("Teología", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_38_data.html");
            //urlDictTemp.Add("Trabajo Social", "http://www.uc.cl/dara/libcursos/periodo22/ua/ua_30_data.html");
            #endregion
            //Cargamos URLs desde archivo:
            string[] listaCarreras = File.ReadAllLines(@".\ListaCursoURL.txt", System.Text.Encoding.Default);
            foreach (string item in listaCarreras)
            {
                if (item.StartsWith("#") || item.Trim() == "")     //Omitimos las lineas vacias o comentadas
                    continue;

                if (item.StartsWith("["))   //Es una linea de configuracion
                {
                    string[] config = item.Trim('[', ']').Split(new string[] { " = " }, StringSplitOptions.None);
                    switch (config[0])
                    {
                        case "Periodo":
                            periodo = config[1];
                            continue;   //Terminamos de parsear, vamos al sgte item.
                        default:
                            throw new FormatException("Error parseando archivo. Linea invalida: " + item);
                    }
                }

                string[] parsedString = item.Split(new string[] { ",\t" }, StringSplitOptions.None);
                if (parsedString.Length != 2)
                    throw new FormatException("El archivo 'ListaCursoURL.txt' tiene un formato invalido. Linea invalida: " + item);

                //Vemos si ya tenemos una url de facultad con ese nombre
                if (urlDict.ContainsKey(parsedString[0].Trim()))
                {
                    urlDict[parsedString[0].Trim()].Add(parsedString[1].Trim());
                }
                else    //Agregamos una nueva entrada con el url
                {
                    urlDict.Add(parsedString[0].Trim(), new List<string>(new string[] { parsedString[1].Trim() }));
                }
            }

            //urlDict = new Dictionary<string, List<string>>(urlDictTemp);  //Hago una copia del temp, asi puedo hacer la variable de la clase urlDict "readonly"
        }

        /// <summary>
        /// EventHandler del trace logger.
        /// </summary>
        void Logger_MessageAdded(string message)
        {
            if (cargarDatosForm != null && cargarDatosForm.Visible)
            {
                //Agregamos el mensaje a la Vista.
                cargarDatosForm.AddLogMessage(message);
            }
        }

        /// <summary>
        /// Inicializa y muestra la interfaz grafica del programa.
        /// </summary>
        public void ShowForm()
        {
            cargarDatosForm = new MainForm(urlDict);
            //Hacemos el wire-up con delegates
            cargarDatosForm.addFromUrlCallback = new AddFromUrlCallback(AddFromUrl);
            cargarDatosForm.saveRamosToFile = new SaveRamosToFile(RamosSave);

            //cargarDatosForm.ShowDialog();
            Application.Run(cargarDatosForm);
        }

        /// <summary> Callback del MainForm:
        /// Agrega los ramos de la Url especificada.
        /// </summary>
        /// <returns>Retorna la cant. de ramos descargados.</returns>
        public int AddFromUrl(string carrera, List<string> urls)
        {
            try
            {
                int count = 0;
                //Para cada URL de la carrera (facultad), descargamos sus datos.
                foreach (string url in urls)
                {
                    List<Ramo> ramosDownloaded = PucParser.Parse(url, carrera);
                    foreach (var ramo in ramosDownloaded)
                    {
                        if (ramos.ContainsKey(ramo.Sigla))  //Actualizar..
                            ramos[ramo.Sigla] = ramo;
                        else
                            ramos.Add(ramo.Sigla, ramo);    //..o agregar uno nuevo.
                    }
                    count += ramosDownloaded.Count;
                }

                //Log info:
                cargarDatosForm.AddLogMessage("Fetch finalizado. Cursos: " + ramos.Keys.Count + ". Errores: " + Logger.Instance.ErrorCount + "\r\n");
                Logger.Instance.ErrorCountReset();
                return count;
            }
            catch (Exception err)
            {
                //Log error:
                cargarDatosForm.AddLogMessage("Ha ocurrido un error no recuperable :" + err.Message);
                return 0;
            }
        }

        /// <summary> Callback del MainForm:
        /// Guarda la lista de ramos en la ruta especificada.
        /// </summary>
        public void RamosSave(string path)
        {
            FileStream fs = new FileStream(path, FileMode.Create);
            //BinaryFormatter formatter = new BinaryFormatter();      //FIX: Usar "*.CSV"
            //formatter.Serialize(fs, ramos);

            XMLWriter myWriter = new XMLWriter();   //Guarda en XML. Puedo "abstraerlo" en interfaz si es necesario despues.
            myWriter.Save(ramos, fs, periodo);

            //Log info:
            cargarDatosForm.AddLogMessage("XML finalizado. Cursos: " + ramos.Keys.Count + ". Errores: " + Logger.Instance.ErrorCount + "\r\n");
            Logger.Instance.ErrorCountReset();
        }


        ////////////
        // MAIN() //
        ////////////

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            MainController controller = new MainController();
            
            controller.ShowForm();
        }
    }
}
